package pathfind;

import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;

/**
 * @author sad
 */
public class mainTestClass {

    static public class Point {

        private int x;
        private int y;

        public Point() {
        }

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 59 * hash + this.x;
            hash = 59 * hash + this.y;
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Point other = (Point) obj;
            if (this.x != other.x) {
                return false;
            }
            if (this.y != other.y) {
                return false;
            }
            return true;
        }
        
        

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }

        @Override
        public String toString() {
            return "["+x+","+y+"]";
        }
        
        

    }

    static public class GridSearch extends AStarAbstract<Point> {

        boolean[][] cells;
        int width;
        int height;
        private Point end;

        public GridSearch(boolean[][] cells, int width, int height, Point end) {
            this.cells = cells;
            this.width = width;
            this.height = height;
            this.end = end;
        }

        @Override
        public AStarAbstract<Point> newInstance(Point end, Object additionalParam) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        protected boolean isGoal(Point node) {
            if(node.getX()==8 && node.getY()==7){
                int x=5;x++;
            }
            return (node.getX() == end.getX()) && (node.getY() == end.getY());
        }

        boolean isCellSuccessor(int x, int y) {
            if (x < 0 || y < 0 || x >= width || y >= height) {
                return false;
            }

            return cells[y][x];
        }

        @Override
        protected List<Point> generateSuccessors(Point node, List<Point> successorsOutputList) {
            int x;
            int y;

            x = node.getX();
            y = node.getY() - 1;
            if (isCellSuccessor(x, y)) {
                successorsOutputList.add(new Point(x, y));
            }

            x = node.getX() - 1;
            y = node.getY();
            if (isCellSuccessor(x, y)) {
                successorsOutputList.add(new Point(x, y));
            }

            x = node.getX() + 1;
            y = node.getY();
            if (isCellSuccessor(x, y)) {
                successorsOutputList.add(new Point(x, y));
            }

            x = node.getX();
            y = node.getY() + 1;
            if (isCellSuccessor(x, y)) {
                successorsOutputList.add(new Point(x, y));
            }
            return successorsOutputList;
        }

        @Override
        protected double g(Point from, Point to) {
            if (from.equals(to)) {
                return 0.0;
            }

            return squaredLength(from, to);
        }

        double squaredLength(Point p1, Point p2) {
            double a = p1.getX() - p2.getX();
            a = a * a;
            double b = p1.getY() - p2.getY();
            b = b * b;
            return a + b;
        }

        @Override
        protected double h(Point from, Point to) {
            return Math.abs(from.getX() - to.getX()) + Math.abs(from.getY() - to.getY());
        }

        @Override
        protected double squaredLengthToGoal(Point cell) {
            double a = end.getX() - cell.getX();
            a = a * a;
            double b = end.getY() - cell.getY();
            b = b * b;
            return a + b;
        }
    }

    static boolean isStart(int[] pixel) {
        return pixel[0] == 255 && pixel[1] == 0 && pixel[2] == 0;
    }

    static boolean isEnd(int[] pixel) {
        return pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 255;
    }

    static boolean isWalkable(int[] pixel) {
        return pixel[0] == 255 && pixel[1] == 255 && pixel[2] == 255;
    }

    public static void main(String[] args) throws IOException {
        BufferedImage bmp = ImageIO.read(new File("d:\\java\\many-different-my-project\\pathfindtry\\pathfindtry\\pathfindtry\\map.bmp"));
        int height = bmp.getHeight();
        int width = bmp.getWidth();

        boolean[][] grid = new boolean[height][];
        Point start = new Point(-1, -1);
        Point end = new Point(-1, -1);
        int[] pixel = new int[4];
        WritableRaster r=bmp.getRaster();
        for (int j = 0; j < height; j++) {
            grid[j] = new boolean[width];
            for (int i = 0; i < width; i++) {
                r.getPixel(i, j, pixel);
                boolean walkable = true;
                if (isStart(pixel)) {
                    start.setX(i);
                    start.setY(j);
                } else if (isEnd(pixel)) {
                    end.setX(i);
                    end.setY(j);
                } else if (!isWalkable(pixel)) {
                    walkable = false;
                }

                grid[j][i] = walkable;
            }
        }

        if (start.getX() == -1 && start.getY() == -1) {
            System.out.println("start Blue pixel is not defined on the map");
            return;
        }

        if (end.getX() == -1 && end.getY() == -1) {
            System.out.println("end Red pixel is not defined on the map");
            return;
        }

        GridSearch search = new GridSearch(grid, width, height, end);
        long mstart=System.currentTimeMillis();
        List<Point> result=search.compute(start);
        long mend=System.currentTimeMillis();
        int countInResult= result!=null?result.size():0;
        System.out.println(mend-mstart+" finded = "+countInResult);
        
        int[]v=new int[]{255,255,0,0};
        for(Point p:result){
            r.setPixel(p.getX(), p.getY(), v);
        }
        
        ImageIO.write(bmp, "bmp", new File("d:\\java\\many-different-my-project\\pathfindtry\\pathfindtry\\pathfindtry\\mapjava.bmp"));
    }
}
